for i, v in ipairs({ "_G", "setmetatable", "rawget" }) do
	env[v] = GLOBAL[v]
end

setmetatable(env,
{
	__index = function(table, key) return rawget(_G, key) end
})

PrefabFiles = {}
Assets = {}

--------------------------------------------------------------------------
--[[ Waffles ]]
--------------------------------------------------------------------------

local function getmemkey(...)
	local key = ""
	for i, v in ipairs(arg) do
		key = key .. "[" .. tostring(v) .. "]"
	end
	return key
end

local function findupvalue(fn, name)
	local i = 1
	while true do
		local upvaluename, upvalue = debug.getupvalue(fn, i)
		if upvalue == nil or upvaluename == name then
			return upvalue, i
		end
		i = i + 1
	end
end

local function getupvalue(fn, ...)
	local prevfn, i
	for _, name in ipairs(arg) do
		prevfn = fn
		fn, i = findupvalue(fn, name)
	end
	return fn, i, prevfn
end

local function setupvalue(fn, ...)
	local upvalue = table.remove(arg)
	local fn, i, prevfn = getupvalue(fn, unpack(arg))
	debug.setupvalue(prevfn, i, upvalue)
end

local function branchupvalue(fn, ...)
	local upvalue = table.remove(arg)
	local fn, i, prevfn = getupvalue(fn, unpack(arg))
	if type(fn) == "function" then
		debug.setupvalue(prevfn, i, function(...)
			return upvalue(fn, ...)
		end)
	else
		debug.setupvalue(prevfn, i, upvalue(fn))
	end
end

local MEMORY = setmetatable({}, { __mode = "v" })

Waffles =
{	
	Load = function(...)	
		return MEMORY[getmemkey(...)]
	end,
		
	Save = function(value, ...)	
		MEMORY[getmemkey(...)] = value
	end,
	
	GetUpvalue = getupvalue,
	
	SetUpvalue = setupvalue,
	
	BranchUpvalue = branchupvalue,
	
	Browse = function(table, ...)
		for i, v in ipairs(arg) do
			if type(table) ~= "table" then
				return
			end
			table = table[v]
		end
		return table
	end,
	
	Parallel = function(root, key, exp, lowpriority)
		if type(root) ~= "table" then
			return
		end
		local old = root[key]
		local fn = old and Waffles.Load("Parallel", old, exp, lowpriority)		
		if old == nil or fn ~= nil then
			root[key] = fn or exp
		else
			if lowpriority then
				root[key] = function(...)
					old(...)
					return exp(...)
				end
			else
				root[key] = function(...)
					exp(...)
					return old(...)
				end
			end
			Waffles.Save(root[key], "Parallel", old, exp, lowpriority)
		end		
		return root[key]
	end,
}

if rawget(_G, "Waffles") ~= nil then
	for name, data in pairs(Waffles) do
		_G["Waffles"][name] = data
	end
else
	rawset(_G, "Waffles", Waffles)
end